#!/usr/bin/env jruby
# -*- coding: us-ascii -*-
# Elizabeth Wiethoff 2008

require 'java'
require 'pp' if $DEBUG

# these mac properties need to come before some of the requires
java.lang.System.setProperty(
  'com.apple.mrj.application.apple.menu.about.name', 'SuperElse')
java.lang.System.setProperty(
  'apple.laf.useScreenMenuBar', 'true')

dir = File.dirname(__FILE__)
require File.join(dir, '..', 'auxil', 'javainclude')
require File.join(dir, '..', 'auxil', 'osdetect')
require File.join(dir, '..', 'gui', 'titledborder')
require File.join(dir, 'superelse')
require File.join(dir, 'outputbox')

########################################

dflt_position = [0, 22]
dflt_size = nil  # let Swing calculate it

$PREFS['busyboxXY'] = dflt_position unless $PREFS.include?('busyboxXY')
$PREFS['busyboxWH'] = dflt_size unless $PREFS.include?('busyboxWH')

p $PREFS if $DEBUG

########################################

class DirectoryLabel < javax.swing.JLabel
  include java.awt.event.ActionListener  # interface
  include_class 'javax.swing.JFileChooser'
  
  def setPath(path)
    @path = path
    setText(@path)
  end
  
  def actionPerformed(event)
    chooser = JFileChooser.new(@path)
    chooser.setDialogTitle("Select #{self.msg}")
    chooser.setApproveButtonText('Select')
    chooser.setFileSelectionMode(JFileChooser::DIRECTORIES_ONLY)
    result = chooser.showOpenDialog(nil)
    if result == JFileChooser::APPROVE_OPTION
      setPath(chooser.getSelectedFile.getPath)
    end
  end
  
  def msg
    raise NotImplementedError, 'override abstract method'
  end
end


class ExamineDirLabel < DirectoryLabel
  def initialize(*args)
    super(*args)
    @path = $PREFS['edir']
  end
  
  def setPath(*args)
    super(*args)
    $PREFS['edir'] = @path
  end
  
  def msg
    'Directory To Examine'
  end
end


class CompareDirLabel < DirectoryLabel
  def initialize(*args)
    super(*args)
    @path = $PREFS['cdir']
  end
  
  def setPath(*args)
    super(*args)
    $PREFS['cdir'] = @path
  end
  
  def msg
    'Directory To Compare'
  end
end

########################################

# interface-like mixin
module JobListenerMixin
  def jobStarted
    setEnabled(false)
  end
  
  def jobEnded
    setEnabled(true)
  end
end

########################################

class ExamineSubsCB < javax.swing.JCheckBox
  include JobListenerMixin  # interface-like mixin
  include java.awt.event.ItemListener  # interface
  def itemStateChanged(event)
    $PREFS['esubdirs'] = !$PREFS['esubdirs']
  end
end

class CompareSubsCB < javax.swing.JCheckBox
  include JobListenerMixin  # interface-like mixin
  include java.awt.event.ItemListener  # interface
  def itemStateChanged(event)
    $PREFS['csubdirs'] = !$PREFS['csubdirs']
  end
end

########################################

class CancelButton < javax.swing.JButton
  include JobListenerMixin  # interface-like mixin gets overridden
  include java.awt.event.ActionListener  # interface
  
  def initialize(*args)
    super(*args)
    @jobListeners = []
    @job = nil
  end
  attr_writer :job
  
  def addJobListener(listener)
    @jobListeners << listener
  end
  
  def actionPerformed(event)
    @job.kill
    puts
    puts 'CANCELED!'
    puts
    @jobListeners.each { |listener| listener.jobEnded }
  end
  
  def jobStarted ; setEnabled(true) ; end  # override
  def jobEnded ; setEnabled(false) ; end  # override
end

########################################

class SearchButton < javax.swing.JButton
  include JobListenerMixin  # interface-like mixin
  include java.awt.event.ActionListener  # interface
  
  def initialize(*args)
    super(*args)
    @jobListeners = []
    @jobKiller = nil
  end
  attr_writer :jobKiller
  
  def addJobListener(listener)
    @jobListeners << listener
  end
  
  def actionPerformed(event)
    @jobListeners.each { |listener| listener.jobStarted }
    @jobKiller.job = Thread.new do
      puts
      df = DupeFinder.new
      df.find_em
      puts
      @jobListeners.each { |listener| listener.jobEnded }
      unless df.data_table.empty?
        launchOutputWindow(df.data_table, DupeFinder.column_info)
      end
    end
  end
end

########################################

class MainFrameListener < java.awt.event.ComponentAdapter
  def componentResized(event)
    c = event.getComponent
    $PREFS['busyboxWH'] = [c.getWidth, c.getHeight]
  end
  
  def componentMoved(event)
    c = event.getComponent
    $PREFS['busyboxXY'] = [c.getX, c.getY]
  end
end

########################################

module BusyBoxJavaClasses
  include_classes 'java.awt', %w[
    BorderLayout Dimension FlowLayout GridLayout Point]
  
  include_classes 'javax.swing', %w[
    BorderFactory
    JButton JCheckBox JFrame JLabel JPanel JScrollPane]
end

JB = BusyBoxJavaClasses

########################################

def defineWidgets
  dE = JB::JPanel.new  # create first for successful checkbox
  dC = JB::JPanel.new  # create first for successful checkbox
  
  bSearch = SearchButton.new('Search')
  bSearch.addActionListener(bSearch)
  
  bCancel = CancelButton.new('Cancel')
  bCancel.addActionListener(bCancel)
  bCancel.setEnabled(false)
  
  titleE = 'Directory To Examine'
  tipE = 'Launch dialog for choosing directory to examine'
  bE = JB::JButton.new('Select...')
  lE = ExamineDirLabel.new($PREFS['edir'])
  cbE = ExamineSubsCB.new('Search subdirectories', 
    $PREFS['esubdirs'])
  bE.addActionListener(lE)
  cbE.addItemListener(cbE)
  
  titleC = 'Directory To Compare'
  tipC = 'Launch dialog for choosing directory to compare'
  bC = JB::JButton.new('Select...')
  lC = CompareDirLabel.new($PREFS['cdir'])
  cbC = CompareSubsCB.new('Search subdirectories', 
    $PREFS['csubdirs'])
  bC.addActionListener(lC)
  cbC.addItemListener(cbC)
  
  bE.extend(JobListenerMixin)
  bC.extend(JobListenerMixin)
  [bSearch, bCancel, bE, bC, cbE, cbC].each do |listener|
    bSearch.addJobListener(listener)
    bCancel.addJobListener(listener)
  end
  bSearch.jobKiller = bCancel
  
  dialogE = assembleDialog(dE, titleE, cbE, lE, bE, tipE)
  dialogC = assembleDialog(dC, titleC, cbC, lC, bC, tipC)
  
  return dialogE, dialogC, bSearch, bCancel
end

########################################

def assembleDialog(dialog, title, checkbox, label, button, toolTip)
  layout = JB::BorderLayout.new
  layout.setVgap(5)
  dialog.setLayout(layout)
  
  dialog.setBorder(bigGrayTitledBorder(title))
  
  checkbox.setHorizontalTextPosition(JB::JCheckBox::LEADING)
  checkbox.setHorizontalAlignment(JB::JCheckBox::RIGHT)
  
  label.setVerticalAlignment(JB::JLabel::TOP)
  spLabel = JB::JScrollPane.new(label)
  spLabel.setPreferredSize(JB::Dimension.new(450, 50))
  spLabel.setMinimumSize(spLabel.getPreferredSize)
  spLabel.setMaximumSize(JB::Dimension.new(9999, 9999))
  
  button.setToolTipText(toolTip)
  pButton = JB::JPanel.new
  pButton.add(button)
  
  dialog.add(checkbox, JB::BorderLayout::NORTH)
  dialog.add(spLabel, JB::BorderLayout::CENTER)
  dialog.add(pButton, JB::BorderLayout::SOUTH)
  return dialog
end

########################################

def assembleBusyBox
  examDirDialog, compDirDialog, bSearch, bCancel = defineWidgets
  
  semibox = JB::JPanel.new(JB::GridLayout.new(2, 1))
  semibox.add(examDirDialog)
  semibox.add(compDirDialog)
  
  searchLayout = JB::FlowLayout.new(JB::FlowLayout::CENTER) #, 25, 5)
  pSearch = JB::JPanel.new(searchLayout)
  if $MSWIN
    pSearch.add(bSearch)
    pSearch.add(bCancel)
  else
    pSearch.add(bCancel)
    pSearch.add(bSearch)
  end
  
  busybox = JB::JPanel.new(JB::BorderLayout.new)
  busybox.add(semibox, JB::BorderLayout::CENTER)
  busybox.add(pSearch, JB::BorderLayout::SOUTH)
  return busybox
end

########################################

def launchMainFrame
  busybox = assembleBusyBox
  
  mainFrame = JB::JFrame.new('SuperElse Busy Box')
  mainFrame.setDefaultCloseOperation(JB::JFrame::EXIT_ON_CLOSE)
  mainFrame.addComponentListener(MainFrameListener.new)
  mainContentPane = mainFrame.getContentPane
  mainContentPane.add(busybox, JB::BorderLayout::CENTER)
  
  wh = $PREFS['busyboxWH']
  if wh
    w, h = wh
    mainFrame.setSize(w, h)
    sleep(2)  # get weird errors if I don't sleep awhile
  else
    mainFrame.pack
  end
  
  x, y = $PREFS['busyboxXY']
  mainFrame.setLocation(JB::Point.new(x, y))
  
  mainFrame.setVisible(true)
  return mainFrame
end

########################################

if $0 == __FILE__
  launchMainFrame
end
